#include "pir_sensor_detect.h"
#include "adc_driver.h"
#include "systime.h"
#include "pir_sensor_sensitivity.h"

#define PIR_CENTER_VOLTAGE 2.5f // 无人状态下，PIR的偏移值,单位V

// 灵敏度阈值--电压值
// #define	    LOW_THRESHOLD_VOLTAGE          0.7f         //0.8f
// #define	    HIGH_THRESHOLD_VOLTAGE         0.4f

#define LOW_THRESHOLD_VOLTAGE 0.8f  // 163
#define HIGH_THRESHOLD_VOLTAGE 0.4f // 82

// #define PIR_CENTER_VAL ((uint16_t)(PIR_CENTER_VOLTAGE * ADC_TOP_DIGITAL / ADC_TOP_VOLTAGE)) // 单位ADC分辨率
static const uint16_t PIR_CENTER_VAL = 512;

// 灵敏度阈值--单位，ADC分辨率
#define PIR_LOW_THRESHOLD 163
#define PIR_HIGH_THRESHOLD 82

#define PIR_SAMPLE_TIME 20 // 单位ms, PIR采样间隔时间

// #define     MAX_WIDTH                       60  //1200ms --period
#define MAX_WIDTH 90 // 1800ms --period
#define MID_WIDTH 10 // 200ms  --continues exceed threshold
#define MIN_WIDTH 2  // 40ms
#define MIN_SPACE 5  // 100ms

typedef enum
{
    PIR_SENSOR_STATE_INIT,   // 初始化状态
    PIR_SENSOR_STATE_DETECT, // 检测状态
    PIR_SENSOR_STATE_OFF,    // 关闭状态
    PIR_SENSOR_STATE_UPDATE, // 更新状态
} pir_sensor_state_e;

typedef struct
{
    uint16_t last_sample;         // 上一次采样值
    uint16_t current_sample;      // 当前采样值
    uint16_t lastlast_high_width; // 上上次高电平持续时间
    uint16_t last_high_width;     // 上次高电平持续时间
    uint16_t current_high_width;  // 当前高电平持续时间
    uint16_t last_low_width;      // 上次低电平持续时间
    uint16_t current_low_width;   // 当前低电平持续时间
} pir_sensor_data_t;

static struct
{
    pir_sensor_state_e state;
    timestamp_t time;
    pir_sensor_data_t data;
    uint16_t detection_threshold;
    uint8_t detection_result;       // PIR感应结果，TRUE--感应有人  FALSE--感应无人
    pir_sensor_enable_e is_enabled; // PIR传感器使能状态
} pir_sensor_ctx;

static void deinit_data(void);
static uint8 is_pir_two_wave_condition(void);
static uint8 is_pir_three_wave_condition(void);
static uint8 PIR_detection_algorlthm(void);

void pir_sensor_detect_init(void)
{
    pir_sensor_ctx.state = PIR_SENSOR_STATE_INIT;

    pir_sensor_ctx.data.last_sample = PIR_CENTER_VAL;
    pir_sensor_ctx.data.current_sample = PIR_CENTER_VAL;
    pir_sensor_ctx.data.lastlast_high_width = 0;
    pir_sensor_ctx.data.last_high_width = 0;
    pir_sensor_ctx.data.current_high_width = 0;
    pir_sensor_ctx.data.last_low_width = 0;
    pir_sensor_ctx.data.current_low_width = 0;

    pir_sensor_ctx.detection_threshold = PIR_HIGH_THRESHOLD;
    pir_sensor_ctx.detection_result = FALSE;
    pir_sensor_ctx.is_enabled = PIR_SENSOR_DISABLED;
}

static void deinit_data(void)
{
    pir_sensor_ctx.data.lastlast_high_width = 0;
    pir_sensor_ctx.data.last_high_width = 0;
    pir_sensor_ctx.data.current_high_width = 0;
    pir_sensor_ctx.data.last_low_width = 0;
    pir_sensor_ctx.data.current_low_width = 0;
}

static void pir_sensor_threshold_config(uint16_t *threshold)
{
    pir_sensitivity_e sensor = get_pir_sensor_sensitivity(); // 获取灵敏度设置
    if (sensor == PIR_SENSITIVITY_OFF)
    {
        return;
    }
    switch (sensor)
    {
    case PIR_SENSITIVITY_LOW:
        *threshold = PIR_LOW_THRESHOLD;
        break;
    case PIR_SENSITIVITY_HIGH:
        *threshold = PIR_HIGH_THRESHOLD;
        break;
    default:
        break;
    }
}

/**
 * \brief   PIR感应结果
 * \param   无
 * \retval  感应有人返回TRUE,感应无人返回FALSE
 */
uint8_t pir_sensor_is_occupied(void)
{

    return pir_sensor_ctx.detection_result;
}

void pir_sensor_set_status(pir_sensor_enable_e status)
{
    if (status == PIR_SENSOR_DISABLED)
    {
        deinit_data();
        pir_sensor_ctx.data.last_sample = PIR_CENTER_VAL;
        pir_sensor_ctx.data.current_sample = PIR_CENTER_VAL;
        pir_sensor_ctx.is_enabled = PIR_SENSOR_DISABLED;
        pir_sensor_ctx.detection_result = FALSE; // 关了之后，感应结果改为FALSE
    }
    else
    {
        pir_sensor_ctx.is_enabled = PIR_SENSOR_ENABLED;
    }
}

void pir_sensor_task(void)
{
    if (pir_sensor_ctx.is_enabled == PIR_SENSOR_DISABLED)
    {
        pir_sensor_ctx.state = PIR_SENSOR_STATE_INIT;
        return;
    }

    switch (pir_sensor_ctx.state)
    {
    case PIR_SENSOR_STATE_INIT:
        if (pir_sensor_ctx.is_enabled)
        {
            pir_sensor_ctx.state = PIR_SENSOR_STATE_DETECT;
        }
        break;
    case PIR_SENSOR_STATE_DETECT:
        if (PIR_SENSITIVITY_OFF == get_pir_sensor_sensitivity())
        {
            deinit_data();
            pir_sensor_ctx.data.last_sample = PIR_CENTER_VAL;
            pir_sensor_ctx.data.current_sample = PIR_CENTER_VAL;
            pir_sensor_ctx.detection_result = FALSE; // 关了之后，感应结果改为FALSE
            pir_sensor_ctx.state = PIR_SENSOR_STATE_OFF;
        }
        else
        {
            pir_sensor_ctx.state = PIR_SENSOR_STATE_UPDATE;
            relative_time_add_ms(&pir_sensor_ctx.time, 20);
        }
        break;
    case PIR_SENSOR_STATE_UPDATE:
        if (is_relative_time_timeout(&pir_sensor_ctx.time))
        { // 每20ms采集计算一次
            pir_sensor_threshold_config(&pir_sensor_ctx.detection_threshold);
            pir_sensor_ctx.detection_result = PIR_detection_algorlthm();
            pir_sensor_ctx.state = PIR_SENSOR_STATE_DETECT;
        }
        break;
    case PIR_SENSOR_STATE_OFF:
        if (PIR_SENSITIVITY_OFF != get_pir_sensor_sensitivity())
        {
            pir_sensor_ctx.state = PIR_SENSOR_STATE_DETECT;
        }
        break;

    default:
        break;
    }
}

/**
 * \brief   (down point)PIR感应有人条件1，MAX_WIDTH(1.2s)周期内，连续两个波形，一个 > 阈值MIN_WIDTH(40ms),一个 > 阈值MIN_SPACE(100ms)
 * \param   无
 * \retval  满足条件1，返回TRUE,不满足返回FALSE
 */
static uint8_t is_pir_two_wave_condition(void)
{
    const uint16_t last_high = pir_sensor_ctx.data.last_high_width;
    const uint16_t current_high = pir_sensor_ctx.data.current_high_width;
    const uint16_t current_low = pir_sensor_ctx.data.current_low_width;

    const uint8_t both_high_valid = (last_high >= MIN_WIDTH) && (current_high >= MIN_WIDTH);
    const uint8_t low_gap_valid = (current_low >= MIN_SPACE) && (last_high >= MIN_SPACE);
    const uint8_t total_time_valid = (last_high + current_low + current_high <= MAX_WIDTH);

    return (both_high_valid && low_gap_valid && total_time_valid);
}

/**
 * \brief   (down point)PIR感应有人条件2，MAX_WIDTH(1.2s)周期内，连续三个波形，均 > 阈值MIN_WIDTH(40ms)
 * \param   无
 * \retval  满足条件2，返回TRUE,不满足返回FALSE
 */
static uint8_t is_pir_three_wave_condition(void)
{

    const uint16_t lastlast_high = pir_sensor_ctx.data.lastlast_high_width;
    const uint16_t last_high = pir_sensor_ctx.data.last_high_width;
    const uint16_t current_high = pir_sensor_ctx.data.current_high_width;
    const uint16_t last_low = pir_sensor_ctx.data.last_low_width;
    const uint16_t current_low = pir_sensor_ctx.data.current_low_width;

    const uint8 all_high_valid = (lastlast_high >= MIN_WIDTH) &&
                                 (last_high >= MIN_WIDTH) &&
                                 (current_high >= MIN_WIDTH);
    const uint8_t total_time_valid = (lastlast_high + last_low + last_high + current_low + current_high <= MAX_WIDTH);

    return (all_high_valid && total_time_valid) ? TRUE : FALSE;
}

static uint8_t PIR_detection_algorlthm(void)
{
    uint8_t res = FALSE;

    pir_sensor_ctx.data.last_sample = pir_sensor_ctx.data.current_sample;
    pir_sensor_ctx.data.current_sample = get_pir_val();

    if (pir_sensor_ctx.data.current_sample >= PIR_CENTER_VAL)
    {
        // 高于中心值：计算正向偏差
        pir_sensor_ctx.data.current_sample -= PIR_CENTER_VAL;
    }
    else
    {
        // 低于中心值：计算反向偏差
        pir_sensor_ctx.data.current_sample = PIR_CENTER_VAL - pir_sensor_ctx.data.current_sample;
    }
    if (pir_sensor_ctx.data.current_sample >= pir_sensor_ctx.detection_threshold)
    { // 高于阈值

        if (pir_sensor_ctx.data.last_sample < pir_sensor_ctx.detection_threshold)
        { // up point
            if (pir_sensor_ctx.data.current_low_width >= MAX_WIDTH)
            { // 采样值连续1.2s小于阈值
                deinit_data();
            }

            pir_sensor_ctx.data.lastlast_high_width = pir_sensor_ctx.data.last_high_width;
            pir_sensor_ctx.data.last_high_width = pir_sensor_ctx.data.current_high_width;
            pir_sensor_ctx.data.current_high_width = 1;
        }
        else
        {
            pir_sensor_ctx.data.current_high_width += (pir_sensor_ctx.data.current_high_width >= MAX_WIDTH) ? 0 : 1;
            if (pir_sensor_ctx.data.current_high_width >= MID_WIDTH)
            {
                res = TRUE;
            }
        }
    }
    else
    { // 低于阈值

        if (pir_sensor_ctx.data.last_sample >= pir_sensor_ctx.detection_threshold)
        { // down point
            if (pir_sensor_ctx.data.current_high_width >= MAX_WIDTH)
            { // 采样值连续1.2s高于阈值
                deinit_data();
            }

            if (is_pir_two_wave_condition() || is_pir_three_wave_condition())
            {
                res = TRUE;
            }
            pir_sensor_ctx.data.last_low_width = pir_sensor_ctx.data.current_low_width;
            pir_sensor_ctx.data.current_low_width = 1;
        }
        else
        {
            pir_sensor_ctx.data.current_low_width += (pir_sensor_ctx.data.current_low_width >= MAX_WIDTH) ? 0 : 1;
        }
    }
    //     pir_sensor_ctx.detection_result = res;
    return res;
}
